﻿namespace EnergyGeneratorSimVisualizer.Serialization
{
    using System;
    using System.IO;
    using System.Xml;
    using System.Xml.Linq;
    using EnergyGeneratorSim.Parameters;

    public static class Serializator
    {
        private static XmlWriterSettings xmlSettings;

        static Serializator()
        {
            xmlSettings = new XmlWriterSettings();
            xmlSettings.ConformanceLevel = ConformanceLevel.Document;
            xmlSettings.Indent = true;
            xmlSettings.NewLineOnAttributes = true;
        }

        public static void Serialize(StreamWriter writer, SimulationParameters parameters)
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }

            if (parameters == null)
            {
                throw new ArgumentNullException("parameters");
            }

            using (var xmlWriter = XmlWriter.Create(writer, xmlSettings))
            {
                WriteSimualationParameters(xmlWriter, parameters);
            }
        }

        public static SimulationParameters Deserialize(StreamReader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("writer");
            }

            SimulationParameters parameters = new SimulationParameters();


            using (var xmlReader = XmlReader.Create(reader))
            {
                var document = XDocument.Load(xmlReader);
                ReadSimualationParameters(document, parameters);
            }

            return parameters;
        }

        private static void WriteSimualationParameters(XmlWriter xmlWriter, SimulationParameters parameters)
        {
            xmlWriter.WriteStartElement("SimulationParameters");

            xmlWriter.WriteElementString("Abstd", parameters.Abstd.ToString("x"));
            xmlWriter.WriteElementString("AnzP", parameters.AnzP.ToString("x"));
            xmlWriter.WriteElementString("dt", parameters.dt.ToString("r"));
            xmlWriter.WriteElementString("PlotAnfang", parameters.PlotAnfang.ToString("x"));
            xmlWriter.WriteElementString("PlotEnde", parameters.PlotEnde.ToString("x"));
            xmlWriter.WriteElementString("PlotStep", parameters.PlotStep.ToString("x"));

            WriteGeneralParameters(xmlWriter, parameters.General);
            WriteInductorParameters(xmlWriter, parameters.Inductor);
            WritePermanentMagnetParameters(xmlWriter, parameters.PermanentMagnet);

            xmlWriter.WriteEndElement();
        }

        private static void ReadSimualationParameters(XDocument document, SimulationParameters parameters)
        {
            var rootNode = document.Element(XName.Get("SimulationParameters"));

            parameters.Abstd = rootNode.ReadULongElement(XName.Get("Abstd"));
            parameters.AnzP = rootNode.ReadULongElement(XName.Get("AnzP"));
            parameters.dt = rootNode.ReadDoubleElement(XName.Get("dt"));
            parameters.PlotAnfang = rootNode.ReadULongElement(XName.Get("PlotAnfang"));
            parameters.PlotEnde = rootNode.ReadULongElement(XName.Get("PlotEnde"));
            parameters.PlotStep = rootNode.ReadULongElement(XName.Get("PlotStep"));

            ReadGeneralParameters(rootNode, parameters.General);
            ReadInductorParameters(rootNode, parameters.Inductor);
            ReadPermanentMagnetParameters(rootNode, parameters.PermanentMagnet);
        }

        private static void WriteGeneralParameters(XmlWriter xmlWriter, GeneralParameters generalParameters)
        {
            xmlWriter.WriteStartElement("General");

            xmlWriter.WriteElementString("CI", generalParameters.CI.ToString("r"));
            xmlWriter.WriteElementString("crAnfang", generalParameters.crAnfang.ToString("r"));
            xmlWriter.WriteElementString("CT", generalParameters.CT.ToString("r"));
            xmlWriter.WriteElementString("Il", generalParameters.Il.ToString("r"));
            xmlWriter.WriteElementString("phipZiel", generalParameters.phipZiel.ToString("r"));
            xmlWriter.WriteElementString("rho", generalParameters.rho.ToString("r"));
            xmlWriter.WriteElementString("rhoMag", generalParameters.rhoMag.ToString("r"));
            xmlWriter.WriteElementString("Rlast", generalParameters.Rlast.ToString("r"));
            xmlWriter.WriteElementString("Uc", generalParameters.Uc.ToString("r"));
            xmlWriter.WriteElementString("UmAn", generalParameters.UmAn.ToString("r"));

            xmlWriter.WriteEndElement();
        }

        private static void ReadGeneralParameters(XElement rootNode, GeneralParameters generalParameters)
        {
            var generalNode = rootNode.Element(XName.Get("General"));

            generalParameters.CI = generalNode.ReadDoubleElement(XName.Get("CI"));
            generalParameters.crAnfang = generalNode.ReadDoubleElement(XName.Get("crAnfang"));
            generalParameters.CT = generalNode.ReadDoubleElement(XName.Get("CT"));
            generalParameters.Il = generalNode.ReadDoubleElement(XName.Get("Il"));
            generalParameters.phipZiel = generalNode.ReadDoubleElement(XName.Get("phipZiel"));
            generalParameters.rho = generalNode.ReadDoubleElement(XName.Get("rho"));
            generalParameters.rhoMag = generalNode.ReadDoubleElement(XName.Get("rhoMag"));
            generalParameters.Rlast = generalNode.ReadDoubleElement(XName.Get("Rlast"));
            generalParameters.Uc = generalNode.ReadDoubleElement(XName.Get("Uc"));
            generalParameters.UmAn = generalNode.ReadDoubleElement(XName.Get("UmAn"));
        }

        private static void WriteInductorParameters(XmlWriter xmlWriter, InductorParameters inductorParameters)
        {
            xmlWriter.WriteStartElement("Inductor");

            xmlWriter.WriteElementString("DD", inductorParameters.DD.ToString("r"));
            xmlWriter.WriteElementString("Nebeninput", inductorParameters.Nebeninput.ToString("x"));
            xmlWriter.WriteElementString("Nebenturbo", inductorParameters.Nebenturbo.ToString("x"));
            xmlWriter.WriteElementString("Ninput", inductorParameters.Ninput.ToString("x"));
            xmlWriter.WriteElementString("Nturbo", inductorParameters.Nturbo.ToString("x"));
            xmlWriter.WriteElementString("Ueberinput", inductorParameters.Ueberinput.ToString("x"));
            xmlWriter.WriteElementString("Ueberturbo", inductorParameters.Ueberturbo.ToString("x"));

            xmlWriter.WriteEndElement();
        }

        private static void ReadInductorParameters(XElement rootNode, InductorParameters inductorParameters)
        {
            var inductorNode = rootNode.Element(XName.Get("Inductor"));

            inductorParameters.DD = inductorNode.ReadDoubleElement(XName.Get("DD"));
            inductorParameters.Nebeninput = inductorNode.ReadIntegerElement(XName.Get("Nebeninput"));
            inductorParameters.Nebenturbo = inductorNode.ReadIntegerElement(XName.Get("Nebenturbo"));
            inductorParameters.Ninput = inductorNode.ReadIntegerElement(XName.Get("Ninput"));
            inductorParameters.Nturbo = inductorNode.ReadIntegerElement(XName.Get("Nturbo"));
            inductorParameters.Ueberinput = inductorNode.ReadIntegerElement(XName.Get("Ueberinput"));
            inductorParameters.Ueberturbo = inductorNode.ReadIntegerElement(XName.Get("Ueberturbo"));
        }

        private static void WritePermanentMagnetParameters(XmlWriter xmlWriter, PermanentMagnetParameters permanentMagnetParameters)
        {
            xmlWriter.WriteStartElement("PermanentMagnet");

            xmlWriter.WriteElementString("Bsw", permanentMagnetParameters.Bsw.ToString("r"));
            xmlWriter.WriteElementString("MEI", permanentMagnetParameters.MEI.ToString("r"));
            xmlWriter.WriteElementString("MEro", permanentMagnetParameters.MEro.ToString("r"));
            xmlWriter.WriteElementString("MEyo", permanentMagnetParameters.MEyo.ToString("r"));

            xmlWriter.WriteEndElement();
        }

        private static void ReadPermanentMagnetParameters(XElement rootNode, PermanentMagnetParameters permanentMagnetParameters)
        {
            var magnetNode = rootNode.Element(XName.Get("PermanentMagnet"));

            permanentMagnetParameters.Bsw = double.Parse(magnetNode.Element(XName.Get("Bsw")).Value);
            permanentMagnetParameters.MEI = double.Parse(magnetNode.Element(XName.Get("MEI")).Value);
            permanentMagnetParameters.MEro = double.Parse(magnetNode.Element(XName.Get("MEro")).Value);
            permanentMagnetParameters.MEyo = double.Parse(magnetNode.Element(XName.Get("MEyo")).Value);
        }
    }
}
